package rmi;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.ResourceBundle;

import annotation.Id;
import annotation.Table;
import bean.RmiBean;

import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;


public class Base {

	String fichierConfig = "base";
	String url = null;
	String user = null;
	String password = null;

	Connection connection = null;

	public Base() {
		ResourceBundle rs = ResourceBundle.getBundle(fichierConfig);
		url = rs.getString("url");
		user = rs.getString("user");
		password = rs.getString("password");
	}

	public Connection getConnection() {
		return connection;
	}

	public void ouvrir() {
		try {
			connection = (Connection) DriverManager.getConnection(url, user, password);
			System.out.println("Base.ouvrir: url = " + url);
		} catch (SQLException e) {
			System.out.println("Base.ouvrir: erreur url = " + url);
		}
	}

	public void fermer() {
		try {
			if (connection != null)
				connection.close();
		} catch (Exception e) {
		}
	}

	public int enregistrer(Object o) {

		/* Mecanisme de reflexion -> analyse complete d'un objet */
		int res = -1;
		String table = null;
		Class c = o.getClass();
		Table ann = (Table) c.getAnnotation(Table.class);
		table = ann.name();
		Field[] champs = c.getDeclaredFields();
		String attrQuery = "(";
		String valQuery = "values(";
		PreparedStatement ps = null;
		int num = 0;
		int nbInputStream = 0;
		try {
			for (Field field : champs) {
				if (!field.isAnnotationPresent(Id.class)) {
					if (num > 0) {
						attrQuery += ",";
						valQuery += ",";
					}
					String nomGetter = "get"
							+ field.getName().substring(0, 1).toUpperCase()
							+ field.getName().substring(1);
					Method mGetter = c.getMethod(nomGetter);
					if (field.getType() == String.class) {
						valQuery += "'" + mGetter.invoke(o) + "'";
					} else if (field.getType() == Integer.class) {
						valQuery += mGetter.invoke(o);
					} else if (field.getType() == Double.class) {
						valQuery += mGetter.invoke(o);
					}
					attrQuery += field.getName();
					num++;
				}
			}
			valQuery += ")";
			attrQuery += ")";
			String query = "insert into " + table + attrQuery + " " + valQuery;
			System.out.println("query = " + query);
			ps = (PreparedStatement) connection.prepareStatement(query);
			res=ps.executeUpdate();

			ps = (PreparedStatement) connection.prepareStatement("select last_insert_id()");
			ResultSet rs = ps.executeQuery();
			rs.next();
			res=rs.getInt(1);
			
			if (ps != null)
				ps.close();
			
	/*		ps = (PreparedStatement) connection.prepareStatement("SELECT * FROM "+table+" ORDER BY id DESC LIMIT 1");
			ResultSet rs =(ResultSet) ps.executeQuery();
			rs.next();
			res=rs.getInt(1);
			
			if (ps != null)
				ps.close();
*/

		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		}

		return res;
	}

	public boolean modifier(Object o) {
		/* Mecanisme de reflexion -> analyse complete d'un objet */

		String table = null;
		Class c = o.getClass();
		Table ann = (Table) c.getAnnotation(Table.class);
		table = ann.name();
		Field[] champs = c.getDeclaredFields();

		String setQuery = "";
		String whereQuery = "";
		PreparedStatement ps = null;
		int nbSet = 0;
		int nbWhere = 0;
		try {
			for (Field field : champs) {
				if (!field.isAnnotationPresent(Id.class)) {
					if (nbSet > 0) {
						setQuery += ", ";
					}
					String nomGetter = "get"
							+ field.getName().substring(0, 1).toUpperCase()
							+ field.getName().substring(1);
					Method mGetter = c.getMethod(nomGetter);
					if (field.getType() == String.class) {
						setQuery += field.getName() + "='" + mGetter.invoke(o)
								+ "'";
					} else if (field.getType() == Integer.class) {
						setQuery += field.getName() + "=" + mGetter.invoke(o);
					} else if (field.getType() == Double.class) {
						setQuery += field.getName() + "=" + mGetter.invoke(o);
					}
					nbSet++;
				} else {
					if (nbWhere > 0) {
						whereQuery += " AND ";
					}
					String nomGetter = "get"
							+ field.getName().substring(0, 1).toUpperCase()
							+ field.getName().substring(1);
					Method mGetter = c.getMethod(nomGetter);
					if (field.getType() == String.class) {
						whereQuery += field.getName() + "=" + mGetter.invoke(o)
								+ "'";
					} else if (field.getType() == Integer.class) {
						whereQuery += field.getName() + "=" + mGetter.invoke(o);
					} else if (field.getType() == Double.class) {
						whereQuery += field.getName() + "=" + mGetter.invoke(o);
					}
					nbWhere++;
				}
			}

			String query = "UPDATE " + table + " SET " + setQuery + " WHERE "
					+ whereQuery;
			System.out.println("query = " + query);
			ps = (PreparedStatement) connection.prepareStatement(query);
			ps.executeUpdate();
			if (ps != null)
				ps.close();
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public boolean supprimer(Object o) {
		/* Mecanisme de reflexion -> analyse complete d'un objet */

		String table = null;
		Class c = o.getClass();
		Table ann = (Table) c.getAnnotation(Table.class);
		table = ann.name();
		Field[] champs = c.getDeclaredFields();

		String whereQuery = "";
		PreparedStatement ps = null;
		int nbWhere = 0;
		try {
			for (Field field : champs) {
				if (field.isAnnotationPresent(Id.class)) {
					if (nbWhere > 0) {
						whereQuery += " AND ";
					}
					String nomGetter = "get"
							+ field.getName().substring(0, 1).toUpperCase()
							+ field.getName().substring(1);
					Method mGetter = c.getMethod(nomGetter);
					if (field.getType() == String.class) {
						whereQuery += field.getName() + "=" + mGetter.invoke(o)
								+ "'";
					} else if (field.getType() == Integer.class) {
						whereQuery += field.getName() + "=" + mGetter.invoke(o);
					} else if (field.getType() == Double.class) {
						whereQuery += field.getName() + "=" + mGetter.invoke(o);
					}
					nbWhere++;
				}
			}

			String query = "DELETE FROM " + table + " WHERE " + whereQuery;
			System.out.println(whereQuery);
			System.out.println("query = " + query);
			ps = (PreparedStatement) connection.prepareStatement(query);
			ps.executeUpdate();
			if (ps != null)
				ps.close();
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public ArrayList lister(Class<? extends RmiBean> classe, String query) {

		ArrayList<Object> res = new ArrayList<Object>();
		Object o;
		PreparedStatement ps = null;
		Field[] champs = classe.getDeclaredFields();

		try {

			ps = (PreparedStatement) connection.prepareStatement(query);
			ResultSet rs = (ResultSet) ps.executeQuery();
			while (rs.next()) {
				o = classe.newInstance();
				for (Field field : champs) {
					String nomChamp = field.getName();
					String nomSetter = "set"
							+ nomChamp.substring(0, 1).toUpperCase()
							+ nomChamp.substring(1);
					Method mSetter = null;

					if (field.getType() == Integer.class) {
						mSetter = classe.getMethod(nomSetter, Integer.class);
						mSetter.invoke(o, rs.getInt(nomChamp));
					} else if (field.getType() == String.class) {
						mSetter = classe.getMethod(nomSetter, String.class);
						mSetter.invoke(o, rs.getString(nomChamp));
					} else if (field.getType() == Double.class) {
						mSetter = classe.getMethod(nomSetter, Double.class);
						mSetter.invoke(o, rs.getDouble(nomChamp));
					}

				}
				res.add(o);
			}
			if (rs != null)
				rs.close();
			if (ps != null)
				ps.close();
		} catch (Exception e) {
			System.out.println("Base.Lister: erreur " + e.getMessage());
		}

		return res;
	}
	
	public RmiBean getRmiBean(Integer id,Class<? extends RmiBean> classe){
		Base base = new Base();
		base.ouvrir();
		Table ann = (Table) classe.getAnnotation(Table.class);
		String query = "SELECT * from "+ann.name();

		if (id != null) {
			query += " WHERE id LIKE " + id ;
		}
		ArrayList<RmiBean> liste = base.lister(classe, query);
		if(liste.size()!=1)return null;
		
		return liste.get(0);
	}
}